package widgets;

import java.util.ArrayList;

import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.MutableTreeNode;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;

import classes.Link;
import classes.MainLink;

/**
 * Simula uma árvore dinâmica, onde pode-se adicionar nodos e excluir nodos.
 * 
 * @author Renato Nunes
 * 
 */
@SuppressWarnings("serial")
public class DynamicTree extends JTree
{
   /**
    * Nodo raiz da árvore.
    */
   private DefaultMutableTreeNode root      = new DefaultMutableTreeNode( "Menu" );

   /**
    * Model da árvore.
    */
   private DefaultTreeModel       treeModel;

   public DynamicTree()
   {
      super();

      treeModel = new DefaultTreeModel( root );
      setModel( treeModel );

      // setEditable( true );
      getSelectionModel().setSelectionMode( TreeSelectionModel.SINGLE_TREE_SELECTION );
      setShowsRootHandles( true );
   }
   
   /**
    * Retorna a raiz da árvore.
    * 
    * @return A raiz da árvore.
    */
   public DefaultMutableTreeNode getRootNode()
   {
      return root;
   }

   /**
    * Carrega a árvore com o menu configurado.
    * 
    * @param links
    *           Links do objeto que está sendo editado.
    */
   public void loadChilds( ArrayList<MainLink> links )
   {
      // Zera a árvore.
      root.removeAllChildren();
      treeModel.reload();
      
      for ( MainLink ml : links )
      {
         DefaultMutableTreeNode parent = addObject( ml );
         for ( Link l : ml.getSubLinks() )
            addObject( parent, l );
      }
   }

   /**
    * Adiciona um nodo na árvore.
    * 
    * @param child
    *           Nome do nodo.
    * @return O nodo adicionado.
    */
   public DefaultMutableTreeNode addObject( Object child )
   {
      DefaultMutableTreeNode parentNode = null;
      TreePath parentPath = getSelectionPath();

      // Busca o nodo pai do nodo que será inserido.
      if (parentPath == null) 
         parentNode = root;
      else
         parentNode = (DefaultMutableTreeNode) parentPath.getLastPathComponent();

      return addObject( parentNode, child );
  }

   /**
    * Adiciona um nodo a um nodo pai.
    * 
    * @param parent
    *           Nodo pai.
    * @param child
    *           Nodo a ser adicionado.
    * @return O nodo adicionado.
    */
   public DefaultMutableTreeNode addObject( DefaultMutableTreeNode parent, Object child )
   {
      DefaultMutableTreeNode childNode = new DefaultMutableTreeNode( child );
      treeModel.insertNodeInto( childNode, parent, parent.getChildCount() );

      scrollPathToVisible( new TreePath( childNode.getPath() ) );

      return childNode;
   }

   /**
    * Remove o nodo selecionado da árvore.
    * 
    * @return O link removido.
    */
   public Link removeObject()
   {
      DefaultMutableTreeNode node = null;
      TreePath parentPath = getSelectionPath();

      if ( parentPath != null )
      {
         node = (DefaultMutableTreeNode) parentPath.getLastPathComponent();
         if ( node != root )
         {
            Link removedNode = (Link) node.getUserObject();
            treeModel.removeNodeFromParent( (MutableTreeNode) node );
            return removedNode;
         }
      }
      
      return null;
   }

   /**
	* Limpa a árvore, removendo todos os nodos exceto a raiz.
	*/
	public void clear()
	{
		for( int i=0; i < root.getChildCount(); i++ )
			treeModel.removeNodeFromParent( (MutableTreeNode) root.getChildAt( i ) );
	}
	
   /**
    * Recarrega a árvore.
    */
   public void refresh()
   {
      treeModel.reload();
      for ( int i = 0; i < getRowCount(); i++ )
         expandRow( i );
   }

   /**
    * Retorna a profundidade do nodo selecionado.
    * 
    * @return Profundidade do nodo selecionado.
    */
   public int getSelectedDepth()
   {
      DefaultMutableTreeNode node = null;
      TreePath parentPath = getSelectionPath();

      if ( parentPath != null )
      {
         node = (DefaultMutableTreeNode) parentPath.getLastPathComponent();
         int depth = node.getLevel();
         return depth;
      }

      return 0;
   }

   /** 
    * Retorna o objeto Link selecionado na árvore.
    * 
	* @return O objeto Link selecionado na árvore ou null caso não exista um objeto selecionado.
	*/
	public Link getSelectedLink()
	{
		DefaultMutableTreeNode node = null;
		TreePath parentPath = getSelectionPath();
		Link link = null;
		
		if ( parentPath != null )
		{
			node = (DefaultMutableTreeNode) parentPath.getLastPathComponent();
			if( node != root )
				link = (Link) node.getUserObject();
		}

		return link;
	}

}
